﻿using System.Collections.Generic;
using System.Linq;
using DotNetNuke.ComponentModel;
using DotNetNuke.Entities.Portals;
using DotNetNuke.Entities.Users;
using DotNetNuke.Security.Permissions;
using DotNetNuke.Services.FileSystem;

namespace BrandonHaynes.Providers.AmazonS3.Permissions
	{
	/// <summary>
	/// A class providing Amazon S3 authorization for folders marked as "S3 Folders" (second-highest bit set);
	/// default core authorization functionality otherwise.
	/// </summary>
	public class AmazonS3AuthorizationProvider : PermissionProvider
		{
		#region Provider Settings
		public Dictionary<string, string> Settings
			{ get { return ComponentFactory.GetComponentSettings<AmazonS3AuthorizationProvider>() as Dictionary<string, string>; } }
		#endregion

		/// <summary>
		/// This override delegates authorization to the Amazon S3 service for those folders that 
		/// are marked as being S3-enabled (second highest-bit set).  Otherwise, we rely on 
		/// base implementation.
		/// </summary>
		/// <param name="folder"></param>
		/// <returns></returns>
		public override bool CanViewFolder(FolderInfo folder)
			{
			var user = UserController.GetCurrentUserInfo();

			bool isAuthorized;

			if (!S3Folder.IsS3FolderOrRoot(folder.FolderID))
				isAuthorized = base.CanViewFolder(folder);
			else if (S3Folder.IsS3Root(folder.FolderID))
				isAuthorized = true;		// Always allow access to the (empty) root S3 folder
			else if (!user.HasS3Service())
				// This may not be technically correct (what do we do with a user that does not
				// have an associated S3 service?).  I guess we rely on Amazon ACL enforcement.
				isAuthorized = PortalController.GetCurrentPortalSettings().S3Service()
					.QueryBucket(folder.ToBucketName()) == LitS3.BucketAccess.Accessible;
			else
				// For a user with a valid S3 association, query S3 for authorization.
				isAuthorized = user
					.S3Service()
					.QueryBucket(folder.ToBucketName()) == LitS3.BucketAccess.Accessible;

			return isAuthorized;
			}

		/// <summary>
		/// We are required to kludge here; the DotNetNuke core does not route all "view" calls
		/// to the CanViewFolder method.  Instead, some will be routed here.  This is unfortunate.
		/// 
		/// For S3-enabled folders, we reroute the call to CanViewFolder.  Otherwise we rely on
		/// base functionality.
		/// </summary>
		public override bool HasFolderPermission(FolderPermissionCollection objFolderPermissions, string PermissionKey)
			{
			// For a "READ"-type permission check on a S3-enabled folder, we delegate to CanViewFolder
			if (PermissionKey == "READ" && objFolderPermissions.Cast<FolderPermissionInfo>().Any(permission => S3Folder.IsS3FolderOrRoot(permission.FolderID)))
				return CanViewFolder(new FolderInfo()
					{
						PortalID = objFolderPermissions[0].PortalID,
						FolderID = objFolderPermissions[0].FolderID,
						FolderPath = objFolderPermissions[0].FolderPath
					});
			else
				return base.HasFolderPermission(objFolderPermissions, PermissionKey);
			}

		public override bool CanAddFolder(FolderInfo folder)
			{
			if (!S3Folder.IsS3FolderOrRoot(folder.FolderID))
				return base.CanAddFolder(folder);
			else
				return false;
			}

		public override bool CanAdminFolder(FolderInfo folder)
			{
			if (!S3Folder.IsS3FolderOrRoot(folder.FolderID))
				return base.CanAdminFolder(folder);
			else
				return false;
			}

		public override bool CanManageFolder(FolderInfo folder)
			{
			if (!S3Folder.IsS3FolderOrRoot(folder.FolderID))
				return base.CanManageFolder(folder);
			else
				return false;
			}

		public override bool CanCopyFolder(FolderInfo folder)
			{
			if (!S3Folder.IsS3FolderOrRoot(folder.FolderID))
				return base.CanCopyFolder(folder);
			else
				return false;
			}

		public override bool CanDeleteFolder(FolderInfo folder)
			{
			if (!S3Folder.IsS3FolderOrRoot(folder.FolderID))
				return base.CanDeleteFolder(folder);
			else
				return false;
			}
		}
	}
